//
// Created by redcat1 on 12.05.2024.
//

#include "test_data_generator.h"
#include "test_dsl.h"
#include "data_generator.h"
#include <iostream>

//
TEST(GetRandomInt, Uniform)
{
  int min = -10;
  int max = 99;
  const int size = 11;
  const int binSize = (max - min + 1)/size;
  int counter[size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  for (int i = 0; i < 110000; i++)
  {
    int value = GetRandomInt(min, max);
    counter[(value - min) / binSize]++;
  }

  for (int i = 0; i < size; i++)
  {
    ASSERT_NEAR(10000, counter[i], 300);
  }
}

//
TEST(GetRandomInt, AllInInterval)
{
  int min = -10, max = 99;
  int counter = 0;
  for (int i = 0; i < 10000; i++)
  {
    int value = GetRandomInt(min, max);
    if (value < min || value > max)
      counter++;
  }
  ASSERT_EQ(0, counter);
}

//
TEST(GetRandomInt, Edges)
{
  int min = -10, max = 50;
  bool hasZero = false, hasMin = false, hasMax = false;
  for (int i = 0; i < 1000; i++)
  {
    int value = GetRandomInt(min, max);
    if (value == 0)
      hasZero = true;
    else if (value == min)
      hasMin = true;
    else if (value == max)
      hasMax = true;
  }

  ASSERT_EQ(true, hasZero);
  ASSERT_EQ(true, hasMin);
  ASSERT_EQ(true, hasMax);
}

//
TEST(GetRandomInt, DegenerateInterval)
{
  ASSERT_EQ(5, GetRandomInt(5, 5));
}

//
TEST(GetRandomDouble, Uniform)
{
  double min = -10.0, max = 100.0;
  const int binCnt = 11;
  const int binSize = 10;
  int counter[binCnt] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  for (int i = 0; i < 110000; i++)
  {
    double value = GetRandomDouble(min, max, 6);
    counter[int(std::floor(value - min)) / binSize]++;
  }

  for (int i = 0; i < binCnt; i++)
  {
    ASSERT_NEAR(10000, counter[i], 300);
  }
}

TEST(GetRandomDouble, AllInInterval)
{
  double min = -10, max = 99;
  int counter = 0;
  for (int i = 0; i < 10000; i++)
  {
    double value = GetRandomDouble(min, max, 4);
    if (value < min || value > max)
      counter++;
  }
  ASSERT_EQ(0, counter);
}

//
TEST(GetRandomDouble, Edges)
{
  double min = -10., max = 100.;
  const double eps = 0.1;
  bool hasZero = false, hasMin = false, hasMax = false;
  for (int i = 0; i < 10000; i++)
  {
    double value = GetRandomDouble(min, max, 4);
    if (fabs(value) < eps)
      hasZero = true;
    if (fabs(value - min) < eps)
      hasMin = true;
    if (fabs(value - max) < eps)
      hasMax = true;
  }

  ASSERT_EQ(true, hasZero);
  ASSERT_EQ(true, hasMin);
  ASSERT_EQ(true, hasMax);
}

//
TEST(GetRandomDouble, DegenerateInterval)
{
  ASSERT_NEAR(5.0, GetRandomDouble(5.0, 5.0, 4), 0.01);
}

//
void RunDataGeneratorTests()
{
  TEST_RUN(GetRandomInt, Uniform);
  TEST_RUN(GetRandomInt, AllInInterval);
  TEST_RUN(GetRandomInt, Edges);
  TEST_RUN(GetRandomInt, DegenerateInterval);

  TEST_RUN(GetRandomDouble, Uniform);
  TEST_RUN(GetRandomDouble, AllInInterval);
  TEST_RUN(GetRandomDouble, Edges);
  TEST_RUN(GetRandomDouble, DegenerateInterval);
}
